// 语音是识别子服务
#pragma once
#include <brpc/server.h>
#include <butil/logging.h>
#include "speech_rec.hpp" //  语音sdk二次封装
#include "etcd.hpp"
#include "logger.hpp"
#include "speech.pb.h"

class SpeechSerImpl : public ProtoAll::SpeechService
{
private:
    Spe_Client::ptr _asr_client; // 语音转换器
public:
    using ptr = std::shared_ptr<SpeechSerImpl>;
    // 依赖注入--解耦
    SpeechSerImpl(const Spe_Client::ptr &client)
        : _asr_client(client)
    {
    }
    ~SpeechSerImpl() {}
    void SpeechRecognition(google::protobuf::RpcController *controller,     // 用于控制 RPC 调用和获取状态信息
                           const ::ProtoAll::SpeechServiceRequest *request, // 客户端发送的请求消息
                           ::ProtoAll::SpeechServiceResponce *response,     /// 需要填充的响应消息
                           ::google::protobuf::Closure *done)               // 回调对象，主要应用于异步请求，处理完成后需要调用它
    {
        brpc::ClosureGuard rpc_guard(done);
        auto Make_Error_Resp = [this](::ProtoAll::SpeechServiceResponce *response,
                                      const std::string& rid,
                                      bool is_success,
                                      const std::string &err_msg)
        {
            response->set_request_id(rid);
            response->set_success(is_success);
            response->set_errmsg(err_msg);
        };
        std::string rid = request->request_id();
        // 取出请求中的语音数据
        const std::string& body = request->speech_content();
        // 调用语音识别，得到响应
        std::string res = _asr_client->Recognition(body);
        if(res.empty())
        {
            LOG_ERROR("语音转换失败!,请求id:{}\n",rid);
            return Make_Error_Resp(response,rid,false,"语音转换失败!");
        }
        response->set_request_id(rid);
        response->set_success(true);
        response->set_result(res);
        return;
    }
};

// 建造者模式 --三个角色!
// 产品、具体建造者
// 声明产品
class SpeechServer
{
private:
    std::shared_ptr<brpc::Server> _server;

public:
    using ptr = std::shared_ptr<SpeechServer>;
    SpeechServer(const std::shared_ptr<brpc::Server> &server)
        : _server(server)
    {
    }
    ~SpeechServer()
    {
    }
    void start()
    {
        _server->RunUntilAskedToQuit();
    }
};

class SpeechServerBuilder
{
private:
    // 作为一个建造者,需要具备"原料"
    // 服务注册
    Registry::ptr _reg_client;   // 服务注册
    Spe_Client::ptr _asr_client; // 语音转换器

    std::shared_ptr<brpc::Server> _server; 
    SpeechSerImpl::ptr _speech_service; // rpc语音转换服务
public:
    SpeechServerBuilder()
    {
    }
    ~SpeechServerBuilder()
    {
    }
    // 建造服务注册中心 -- key: 服务的地址   val：服务的名称
    void MakeRegClientPtr(const std::string &host,const std::string& key,const std::string& val)
    {
        _reg_client = std::make_shared<Registry>(host);
        _reg_client->registry(key,val);
    }
    // 建造语音转换
    void MakeTransformerPtr(const std::string &app_id,
                            const std::string &api_key,
                            const std::string &secret_key)
    {
        _asr_client = std::make_shared<Spe_Client>(app_id, api_key, secret_key);
    }
    // 建造brpc服务器 -- port：rpc服务器的监听端口  
    void MakeBrpcServerPtr(int port,int con_timeout,int thread_cnt)
    {
        _speech_service = std::make_shared<SpeechSerImpl>(_asr_client);
        _server = std::make_shared<brpc::Server>();
        int n = _server->AddService(_speech_service.get(), brpc::ServiceOwnership::SERVER_DOESNT_OWN_SERVICE);
        if (n < 0)
        {
            LOG_ERROR("添加Rpc服务失败!\n");
            abort();
        }
        // 4. 启动服务器
        brpc::ServerOptions options;
        options.idle_timeout_sec = con_timeout;      // 连接空闲超时时间-超时后连接被关闭   -1表示禁用连接空闲超时
        options.num_threads = thread_cnt;            // io线程数量
        n = _server->Start(port, &options); // 10010
        if (n < 0)
        {
            LOG_ERROR("启动服务器失败!\n");
            abort();
        }
    }
    SpeechServer::ptr Build()
    {
        if (!_reg_client)
        {
            LOG_ERROR("服务注册中心句柄没有初始化!\n");
            abort();
        }
        if (!_asr_client)
        {
            LOG_ERROR("语音转换器句柄没有初始化!\n");
            abort();
        }
        if (!_server)
        {
            LOG_ERROR("rpc句柄没有初始化!\n");
            abort();
        }
        auto server = std::make_shared<SpeechServer>(_server);
        return server;
    }
};